From dc133446a4385ca1d056ccb499e3546231f5b440 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 29 Feb 2008 09:18:01 -0700 Subject: [PATCH] [IA64] kexec: Unpin TLB in the hypervisor The dom0 relocate_new_kernel code makes a large number of assumptions about various compile time constants, and thus assumes that these constants are the same for the hypervisor and dom0. Despite extensive #ifdef work this has proved to be both fragile and incomplete. This patch changes things around so that the unpinning work is done by code provided by the hypervisor, reusing existing code there. Apart from being a solution that works, its also likely a much more maintainable solution, as as TLB changes in the hypervisor code are made, the code paths in the hypervisor are much more likely to be checked than this one which lies in a completely different tree. There is also a dom0 Linux kernel portion to this patch. Its commit message has comments detailing various implementation issues. See linux-2.6.18-xen.hg ee7015727bd15e80e17e725f70c0a5336e45607a Signed-off-by: Simon Horman --- xen/arch/ia64/xen/machine_kexec.c | 25 ++------------ xen/arch/ia64/xen/relocate_kernel.S | 51 +++++++++++++++++++++++++++++ xen/include/asm-ia64/kexec.h | 6 ++-- 3 files changed, 57 insertions(+), 25 deletions(-) diff --git a/xen/arch/ia64/xen/machine_kexec.c b/xen/arch/ia64/xen/machine_kexec.c index b9c78fd9ed..849a395f23 100644 --- a/xen/arch/ia64/xen/machine_kexec.c +++ b/xen/arch/ia64/xen/machine_kexec.c @@ -25,17 +25,6 @@ #include #include -typedef asmlinkage NORET_TYPE void (*relocate_new_kernel_t)( - unsigned long indirection_page, - unsigned long start_address, - struct ia64_boot_param *boot_param, - unsigned long pal_addr, - unsigned long cpu_data_pa, - unsigned long kernel_start, - unsigned long page_offset, - unsigned long vhpt) - ATTRIB_NORET; - #define kexec_flush_icache_page(page) \ do { \ unsigned long page_addr = (unsigned long)page_address(page); \ @@ -54,12 +43,6 @@ void machine_kexec_unload(int type, int slot, xen_kexec_image_t *image) static void ia64_machine_kexec(struct unw_frame_info *info, void *arg) { xen_kexec_image_t *image = arg; - relocate_new_kernel_t rnk; - unsigned long code_addr = (unsigned long) - __va(image->reboot_code_buffer); - unsigned long cpu_data_pa = (unsigned long) - __pa(cpu_data(smp_processor_id())); - unsigned long vhpt; int ii; /* Interrupts aren't acceptable while we reboot */ @@ -84,12 +67,8 @@ static void ia64_machine_kexec(struct unw_frame_info *info, void *arg) while (ia64_get_ivr() != IA64_SPURIOUS_INT_VECTOR) ia64_eoi(); platform_kernel_launch_event(); - vhpt = __va_ul(vcpu_vhpt_maddr(current)); - BUG_ON(!vhpt); - rnk = (relocate_new_kernel_t)&code_addr; - (*rnk)(image->indirection_page, image->start_address, ia64_boot_param, - GRANULEROUNDDOWN((unsigned long) pal_vaddr), cpu_data_pa, - KERNEL_START, PAGE_OFFSET, vhpt); + relocate_new_kernel(image->indirection_page, image->start_address, + __pa(ia64_boot_param), image->reboot_code_buffer); BUG(); } diff --git a/xen/arch/ia64/xen/relocate_kernel.S b/xen/arch/ia64/xen/relocate_kernel.S index 8b440a5f38..b0ab86c3d4 100644 --- a/xen/arch/ia64/xen/relocate_kernel.S +++ b/xen/arch/ia64/xen/relocate_kernel.S @@ -16,6 +16,57 @@ #include #include +/* relocate_new_kernel + * + * Do all the unpinning here, as the hypervisor has all the relevant + * variables and constants. Then go into the reboot_code_buffer to + * relocaate the new kernel and then branch into purgatory. + * + * Based on ia64_jump_to_sal + * + * in0: indirection_page + * in1: start_address + * in2: boot_param + * in2: dom0_relocate_new_kernel + */ +GLOBAL_ENTRY(relocate_new_kernel) + .prologue + alloc r31=ar.pfs,4,0,4,0 + .body + rsm psr.i | psr.ic +{ + flushrs + srlz.i +} + movl r18=tlb_purge_done;; + DATA_VA_TO_PA(r18);; + mov b1=r18 // Return location + movl r18=ia64_do_tlb_purge;; + DATA_VA_TO_PA(r18);; + mov b2=r18 // doing tlb_flush work + mov ar.rsc=0 // Put RSE in enforced lazy, LE mode + movl r17=1f;; + DATA_VA_TO_PA(r17);; + mov cr.iip=r17 + movl r16=IA64_PSR_AC|IA64_PSR_BN|IA64_PSR_IC;; + mov cr.ipsr=r16 + mov cr.ifs=r0;; + rfi;; +1: + /* Invalidate all TLB data/inst */ + br.sptk.many b2;; // jump to tlb purge code + +tlb_purge_done: + mov out0=in0 // out3 is ignored and thus can be garbage + mov out1=in1 + mov out2=in2 + mov b1=in3 + ;; + br.sptk.many b1;; // jump to dom0-supplied relocate_new_kernel + + /* We should never get here */ +END(relocate_new_kernel) + GLOBAL_ENTRY(ia64_dump_cpu_regs) .prologue alloc loc0=ar.pfs,1,2,0,0 diff --git a/xen/include/asm-ia64/kexec.h b/xen/include/asm-ia64/kexec.h index 33e94c26e5..97d892838f 100644 --- a/xen/include/asm-ia64/kexec.h +++ b/xen/include/asm-ia64/kexec.h @@ -5,8 +5,10 @@ #include extern const unsigned int relocate_new_kernel_size; -extern void relocate_new_kernel(unsigned long, unsigned long, - struct ia64_boot_param *, unsigned long); +extern void relocate_new_kernel(unsigned long indirection_page, + unsigned long start_address, + unsigned long boot_param, + unsigned long dom0_relocate_new_kernel); void crash_save_xen_notes(void); void machine_kexec(xen_kexec_image_t *image); unsigned long kdump_find_rsvd_region(unsigned long size, -- 2.30.2